using System;
using System.Linq;
using Synapse.Framework.Notifier;
using Synapse.Framework.Pipe.Attributes;
using Synapse.Framework.Pipe.BusinessObjects;
using Synapse.Framework.Pipe.Operations;

namespace Synapse.Framework.Pipe.Filters
{
    public class FilterAOP<TInput, TOutput> : IFilter
    {
        private readonly IFilter inner;
        private readonly Func<TInput, _<TOutput>> process;

        public FilterAOP(IFilter inner)
        {
            this.inner = inner;
        }

        public FilterAOP(IOperation<TInput, TOutput> operation, INotifier notifier)
            : this(new Filter<TInput, TOutput>(operation,notifier))
        {
            process = operation.Process;
        }

        public IBusinessObject Execute(IBusinessObject input)
        {
            var attributes = process.Method
                .GetCustomAttributes(typeof(ActionAttibute), false)
                .Cast<ActionAttibute>()
                .ToArray();

            if (input == null) return new BlockObject();

            var output = inner.Execute(
                attributes.Aggregate(input,
                                     (current, attibute) =>attibute.Before((BusinessObjet<TInput>) current)));

            if (output == null) return new BlockObject();

            return attributes.Aggregate(output,
                                        (current, attibute) => attibute.After((BusinessObjet<TOutput>) current));
        }
    }
}